home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_emacs.idb / usr / freeware / share / emacs / 19.34 / lisp / ediff.el.z / ediff.el
Encoding:
Text File  |  1998-10-28  |  41.8 KB  |  1,238 lines

  1. ;;; ediff.el --- a comprehensive visual interface to diff & patch
  2.  
  3. ;; Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
  4.  
  5. ;; Author: Michael Kifer <kifer@cs.sunysb.edu>
  6. ;; Created: February 2, 1994
  7. ;; Keywords: comparing, merging, patching, version control.
  8.  
  9. (defconst ediff-version "2.61" "The current version of Ediff")
  10. (defconst ediff-date "June 10, 1996" "Date of last update")  
  11.  
  12.  
  13. ;; This file is part of GNU Emacs.
  14.  
  15. ;; GNU Emacs is free software; you can redistribute it and/or modify
  16. ;; it under the terms of the GNU General Public License as published by
  17. ;; the Free Software Foundation; either version 2, or (at your option)
  18. ;; any later version.
  19.  
  20. ;; GNU Emacs is distributed in the hope that it will be useful,
  21. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23. ;; GNU General Public License for more details.
  24.  
  25. ;; You should have received a copy of the GNU General Public License
  26. ;; along with GNU Emacs; see the file COPYING.  If not, write to the
  27. ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  28. ;; Boston, MA 02111-1307, USA.
  29.  
  30. ;;; Commentary:
  31.  
  32. ;; Never read that diff output again!
  33. ;; Apply patch interactively!
  34. ;; Merge with ease!
  35.  
  36. ;; This package provides a convenient way of simultaneous browsing through
  37. ;; the differences between a pair (or a triple) of files or buffers.  The
  38. ;; files being compared, file-A, file-B, and file-C (if applicable) are
  39. ;; shown in separate windows (side by side, one above the another, or in
  40. ;; separate frames), and the differences are highlighted as you step
  41. ;; through them.  You can also copy difference regions from one buffer to
  42. ;; another (and recover old differences if you change your mind).
  43.  
  44. ;; Ediff also supports merging operations on files and buffers, including
  45. ;; merging using ancestor versions. Both comparison and merging operations can
  46. ;; be performed on directories, i.e., by pairwise comparison of files in those
  47. ;; directories.
  48.  
  49. ;; In addition, Ediff can apply a patch to a file and then let you step
  50. ;; though both files, the patched and the original one, simultaneously,
  51. ;; difference-by-difference.  You can even apply a patch right out of a
  52. ;; mail buffer, i.e., patches received by mail don't even have to be saved.
  53. ;; Since Ediff lets you copy differences between buffers, you can, in
  54. ;; effect, apply patches selectively (i.e., you can copy a difference
  55. ;; region from file_orig to file, thereby undoing any particular patch that
  56. ;; you don't like).
  57.  
  58. ;; Ediff is aware of version control, which lets the user compare
  59. ;; files with their older versions. Ediff can also work with remote and
  60. ;; compressed files. Details are given below.
  61.  
  62. ;; Finally, Ediff supports directory-level comparison, merging and patching.
  63. ;; See the on-line manual for details.
  64.  
  65. ;; This package builds upon the ideas borrowed from emerge.el and several
  66. ;; Ediff's functions are adaptations from emerge.el. Much of the functionality
  67. ;; Ediff provides is also influenced by emerge.el.
  68.  
  69. ;; The present version of Ediff supersedes Emerge. It provides a superior user
  70. ;; interface and has numerous major features not found in Emerge. In
  71. ;; particular, it can do patching, and 2-way and 3-way file comparison,
  72. ;; merging, and directory operations.
  73.  
  74.  
  75.  
  76. ;;; Bugs:
  77.  
  78. ;;  1. The undo command doesn't restore deleted regions well. That is, if
  79. ;;  you delete all characters in a difference region and then invoke
  80. ;;  `undo', the reinstated text will most likely be inserted outside of
  81. ;;  what Ediff thinks is the current difference region. (This problem
  82. ;;  doesn't seem to exist with XEmacs.)
  83. ;;
  84. ;;  If at any point you feel that difference regions are no longer correct,
  85. ;;  you can hit '!' to recompute the differences.
  86.  
  87. ;;  2. On a monochrome display, the repertoire of faces with which to
  88. ;;  highlight fine differences is limited. By default, Ediff is using
  89. ;;  underlining. However, if the region is already underlined by some other
  90. ;;  overlays, there is no simple way to temporarily remove that residual
  91. ;;  underlining. This problem occurs when a buffer is highlighted with
  92. ;;  hilit19.el or font-lock.el packages. If this residual highlighting gets
  93. ;;  in the way, you can do the following. Both font-lock.el and hilit19.el
  94. ;;  provide commands for unhighlighting buffers. You can either place these
  95. ;;  commands in `ediff-prepare-buffer-hook' (which will unhighlight every
  96. ;;  buffer used by Ediff) or you can execute them interactively, at any time
  97. ;;  and on any buffer.
  98.  
  99.  
  100. ;;; Acknowledgements:
  101.  
  102. ;; Ediff was inspired by Dale R. Worley's <drw@math.mit.edu> emerge.el.
  103. ;; Ediff would not have been possible without the help and encouragement of
  104. ;; its many users. See Ediff on-line Info for the full list of those who
  105. ;; helped. Improved defaults in Ediff file-name reading commands.
  106.  
  107. ;;; Code:
  108.  
  109. (require 'ediff-init)
  110. ;; ediff-mult is always required, because of the registry stuff
  111. (require 'ediff-mult)
  112.  
  113. (eval-when-compile
  114.   (load "dired")
  115.   (load-file "./ediff-ptch.el")
  116.   (load-file "./ediff-vers.el")
  117.   (load "pcl-cvs" 'noerror))
  118.  
  119. (defvar ediff-use-last-dir nil
  120.   "*If t, Ediff uses previous directory as default when reading file name.")
  121.   
  122. (defvar ediff-last-dir-A nil
  123.   "Last directory used by an Ediff command for file-A.")
  124. (defvar ediff-last-dir-B nil
  125.   "Last directory used by an Ediff command for file-B.")
  126. (defvar ediff-last-dir-C nil
  127.   "Last directory used by an Ediff command for file-C.")
  128. (defvar ediff-last-dir-ancestor nil
  129.   "Last directory used by an Ediff command for the ancestor file.")
  130.  
  131. ;; Some defvars to reduce the number of compiler warnings
  132. (defvar cvs-cookie-handle)
  133. (defvar ediff-last-dir-patch)
  134. (defvar ediff-patch-default-directory)
  135. ;; end of compiler pacifier
  136.  
  137.  
  138. ;; Used as a startup hook to set `_orig' patch file read-only.
  139. (defun ediff-set-read-only-in-buf-A ()
  140.   (ediff-eval-in-buffer ediff-buffer-A
  141.     (toggle-read-only 1)))
  142.  
  143. ;; Return a plausible default for ediff's first file:
  144. ;; In dired, return the file name under the point, unless it is a directory
  145. ;; If the buffer has a file name, return that file name.
  146. (defun ediff-get-default-file-name ()
  147.   (cond ((eq major-mode 'dired-mode)
  148.      (let ((f (dired-get-filename nil 'no-error)))
  149.        (if (and (stringp f) (not (file-directory-p f)))
  150.            f)))
  151.     ((buffer-file-name (current-buffer))
  152.      (file-name-nondirectory (buffer-file-name (current-buffer))))
  153.     ))
  154.  
  155. ;;; Compare files/buffers
  156.  
  157. ;;;###autoload
  158. (defun ediff-files (file-A file-B &optional startup-hooks)
  159.   "Run Ediff on a pair of files, FILE-A and FILE-B."
  160.   (interactive
  161.    (let ((dir-A (if ediff-use-last-dir
  162.             ediff-last-dir-A
  163.           default-directory))
  164.      dir-B f)
  165.      (list (setq f (ediff-read-file-name
  166.             "File A to compare" dir-A 
  167.             (ediff-get-default-file-name)))
  168.        (ediff-read-file-name "File B to compare" 
  169.                  (setq dir-B
  170.                        (if ediff-use-last-dir
  171.                        ediff-last-dir-B 
  172.                      (file-name-directory f)))
  173.                  (progn
  174.                    (setq file-name-history
  175.                      (cons (ediff-abbreviate-file-name
  176.                         (expand-file-name
  177.                          (file-name-nondirectory f)
  178.                          dir-B))
  179.                            file-name-history))
  180.                    f))
  181.        )))
  182.   (ediff-files-internal file-A 
  183.             (if (file-directory-p file-B)
  184.                 (expand-file-name
  185.                  (file-name-nondirectory file-A) file-B)
  186.               file-B)
  187.             nil ; file-C
  188.             startup-hooks
  189.             'ediff-files))
  190.   
  191. ;;;###autoload
  192. (defun ediff-files3 (file-A file-B file-C &optional startup-hooks)
  193.   "Run Ediff on three files, FILE-A, FILE-B, and FILE-C."
  194.   (interactive
  195.    (let ((dir-A (if ediff-use-last-dir
  196.             ediff-last-dir-A
  197.           default-directory))
  198.      dir-B dir-C f ff)
  199.      (list (setq f (ediff-read-file-name
  200.             "File A to compare" dir-A
  201.             (ediff-get-default-file-name)))
  202.        (setq ff (ediff-read-file-name "File B to compare" 
  203.                       (setq dir-B
  204.                         (if ediff-use-last-dir
  205.                             ediff-last-dir-B
  206.                           (file-name-directory f)))
  207.                       (progn
  208.                         (setq file-name-history
  209.                           (cons
  210.                            (ediff-abbreviate-file-name
  211.                             (expand-file-name
  212.                              (file-name-nondirectory f)
  213.                              dir-B))
  214.                            file-name-history))
  215.                         f)))
  216.        (ediff-read-file-name "File C to compare" 
  217.                  (setq dir-C (if ediff-use-last-dir
  218.                          ediff-last-dir-C
  219.                            (file-name-directory ff)))
  220.                  (progn
  221.                    (setq file-name-history
  222.                      (cons (ediff-abbreviate-file-name
  223.                         (expand-file-name
  224.                          (file-name-nondirectory ff)
  225.                          dir-C))
  226.                            file-name-history))
  227.                    ff))
  228.        )))
  229.   (ediff-files-internal file-A 
  230.             (if (file-directory-p file-B)
  231.                 (expand-file-name
  232.                  (file-name-nondirectory file-A) file-B)
  233.               file-B)
  234.             (if (file-directory-p file-C)
  235.                 (expand-file-name
  236.                  (file-name-nondirectory file-A) file-C)
  237.               file-C)
  238.             startup-hooks
  239.             'ediff-files3))
  240.  
  241. ;;;###autoload
  242. (defalias 'ediff3 'ediff-files3)
  243.  
  244.  
  245. ;; Visit FILE and arrange its buffer to Ediff's liking. 
  246. ;; FILE is actually a variable symbol that must contain a true file name.
  247. ;; BUFFER-NAME is a variable symbol, which will get the buffer object into
  248. ;; which FILE is read.
  249. ;; LAST-DIR is the directory variable symbol where FILE's
  250. ;; directory name should be returned. HOOKS-VAR is a variable symbol that will
  251. ;; be assigned the hook to be executed after `ediff-startup' is finished.
  252. ;; `ediff-find-file' arranges that the temp files it might create will be
  253. ;; deleted.
  254. (defun ediff-find-file (file-var buffer-name &optional last-dir hooks-var)
  255.   (let* ((file (symbol-value file-var))
  256.      (file-magic (find-file-name-handler file 'find-file-noselect))
  257.      (temp-file-name-prefix (file-name-nondirectory file)))
  258.     (cond ((not (file-readable-p file))
  259.        (error "File `%s' does not exist or is not readable" file))
  260.       ((file-directory-p file)
  261.        (error "File `%s' is a directory" file)))
  262.     
  263.     ;; some of the commands, below, require full file name
  264.     (setq file (expand-file-name file))
  265.   
  266.     ;; Record the directory of the file
  267.     (if last-dir
  268.     (set last-dir (expand-file-name (file-name-directory file))))
  269.     
  270.     ;; Setup the buffer
  271.     (set buffer-name (find-file-noselect file))
  272.   
  273.     (ediff-eval-in-buffer (symbol-value buffer-name)
  274.       (widen) ; Make sure the entire file is seen
  275.       (cond (file-magic  ;; file has handler, such as jka-compr-handler or
  276.          ;; ange-ftp-hook-function--arrange for temp file
  277.          (ediff-verify-file-buffer 'magic)
  278.          (setq file
  279.            (ediff-make-temp-file
  280.             (current-buffer) temp-file-name-prefix))
  281.          (set hooks-var (cons (` (lambda () (delete-file (, file))))
  282.                   (symbol-value hooks-var))))
  283.         ;; file processed via auto-mode-alist, a la uncompress.el
  284.         ((not (equal (file-truename file)
  285.              (file-truename (buffer-file-name))))
  286.          (setq file
  287.            (ediff-make-temp-file
  288.             (current-buffer) temp-file-name-prefix))
  289.          (set hooks-var (cons (` (lambda () (delete-file (, file))))
  290.                   (symbol-value hooks-var))))
  291.         (t ;; plain file---just check that the file matches the buffer
  292.          (ediff-verify-file-buffer))))
  293.     (set file-var file)))
  294.  
  295. (defun ediff-files-internal (file-A file-B file-C startup-hooks job-name)
  296.   (let (buf-A buf-B buf-C)
  297.     (message "Reading file %s ... " file-A)
  298.     ;;(sit-for 0)
  299.     (ediff-find-file 'file-A 'buf-A 'ediff-last-dir-A 'startup-hooks)
  300.     (message "Reading file %s ... " file-B)
  301.     ;;(sit-for 0)
  302.     (ediff-find-file 'file-B 'buf-B 'ediff-last-dir-B 'startup-hooks)
  303.     (if (stringp file-C)
  304.     (progn
  305.       (message "Reading file %s ... " file-C)
  306.       ;;(sit-for 0)
  307.       (ediff-find-file
  308.        'file-C 'buf-C
  309.        (if (eq job-name 'ediff-merge-files-with-ancestor)
  310.            'ediff-last-dir-ancestor 'ediff-last-dir-C)
  311.        'startup-hooks)))
  312.     (ediff-setup buf-A file-A
  313.          buf-B file-B
  314.          buf-C file-C
  315.          startup-hooks
  316.          (list (cons 'ediff-job-name job-name)))))
  317.   
  318.  
  319. ;;;###autoload
  320. (defalias 'ediff 'ediff-files)
  321.  
  322.  
  323. ;;;###autoload
  324. (defun ediff-buffers (buffer-A buffer-B &optional startup-hooks job-name)
  325.   "Run Ediff on a pair of buffers, BUFFER-A and BUFFER-B."
  326.   (interactive 
  327.    (let (bf)
  328.      (list (setq bf (read-buffer "Buffer A to compare: "
  329.                  (ediff-other-buffer "") t))
  330.        (read-buffer "Buffer B to compare: "
  331.             (progn
  332.               ;; realign buffers so that two visible bufs will be
  333.               ;; at the top
  334.               (save-window-excursion (other-window 1))
  335.               (ediff-other-buffer bf))
  336.             t))))
  337.   (or job-name (setq job-name 'ediff-buffers))
  338.   (ediff-buffers-internal buffer-A buffer-B nil startup-hooks job-name))
  339.  
  340. ;;;###autoload
  341. (defalias 'ebuffers 'ediff-buffers)
  342.  
  343.       
  344. ;;;###autoload
  345. (defun ediff-buffers3 (buffer-A buffer-B buffer-C
  346.                  &optional startup-hooks job-name)
  347.   "Run Ediff on three buffers, BUFFER-A, BUFFER-B, and BUFFER-C."
  348.   (interactive 
  349.    (let (bf bff)
  350.      (list (setq bf (read-buffer "Buffer A to compare: "
  351.                  (ediff-other-buffer "") t))
  352.        (setq bff (read-buffer "Buffer B to compare: "
  353.                   (progn
  354.                     ;; realign buffers so that two visible
  355.                     ;; bufs will be at the top
  356.                     (save-window-excursion (other-window 1))
  357.                     (ediff-other-buffer bf))
  358.                   t))
  359.        (read-buffer "Buffer C to compare: "
  360.                   (progn
  361.                     ;; realign buffers so that three visible
  362.                     ;; bufs will be at the top
  363.                     (save-window-excursion (other-window 1))
  364.                     (ediff-other-buffer (list bf bff)))
  365.                   t)
  366.        )))
  367.   (or job-name (setq job-name 'ediff-buffers3))
  368.   (ediff-buffers-internal buffer-A buffer-B buffer-C startup-hooks job-name))
  369.  
  370. ;;;###autoload
  371. (defalias 'ebuffers3 'ediff-buffers3)
  372.       
  373.  
  374.             
  375. (defun ediff-buffers-internal (buf-A buf-B buf-C startup-hooks job-name)
  376.   (let* ((buf-A-file-name (buffer-file-name (get-buffer buf-A)))
  377.      (buf-B-file-name (buffer-file-name (get-buffer buf-B)))
  378.      (buf-C-is-alive (ediff-buffer-live-p buf-C))
  379.      (buf-C-file-name (if buf-C-is-alive
  380.                   (buffer-file-name (get-buffer buf-B))))
  381.      file-A file-B file-C)
  382.     (if (not (ediff-buffer-live-p buf-A))
  383.     (error "Buffer %S doesn't exist" buf-A))
  384.     (if (not (ediff-buffer-live-p buf-B))
  385.     (error "Buffer %S doesn't exist" buf-B))
  386.     (let ((ediff-job-name job-name))
  387.       (if (and ediff-3way-comparison-job
  388.            (not buf-C-is-alive))
  389.       (error "Buffer %S doesn't exist" buf-C)))
  390.     (if (stringp buf-A-file-name)
  391.     (setq buf-A-file-name (file-name-nondirectory buf-A-file-name)))
  392.     (if (stringp buf-B-file-name)
  393.     (setq buf-B-file-name (file-name-nondirectory buf-B-file-name)))
  394.     (if (stringp buf-C-file-name)
  395.     (setq buf-C-file-name (file-name-nondirectory buf-C-file-name)))
  396.     
  397.     (setq file-A (ediff-make-temp-file buf-A buf-A-file-name)
  398.       file-B (ediff-make-temp-file buf-B buf-B-file-name))
  399.     (if buf-C-is-alive
  400.     (setq file-C (ediff-make-temp-file buf-C buf-C-file-name)))
  401.       
  402.     (ediff-setup (get-buffer buf-A) file-A
  403.          (get-buffer buf-B) file-B
  404.          (if buf-C-is-alive (get-buffer buf-C))
  405.          file-C
  406.          (cons (` (lambda ()
  407.                 (delete-file (, file-A))
  408.                 (delete-file (, file-B))
  409.                 (if (stringp (, file-C)) (delete-file (, file-C)))
  410.                 ))
  411.                startup-hooks)
  412.          (list (cons 'ediff-job-name job-name))
  413.          )))
  414.  
  415.  
  416. ;;; Directory and file group operations
  417.  
  418. ;; Get appropriate default name for directory:
  419. ;; If ediff-use-last-dir, use ediff-last-dir-A.
  420. ;; In dired mode, use the directory that is under the point (if any);
  421. ;; otherwise, use default-directory
  422. (defun ediff-get-default-directory-name ()
  423.   (cond (ediff-use-last-dir ediff-last-dir-A)
  424.     ((eq major-mode 'dired-mode)
  425.      (let ((f (dired-get-filename nil 'noerror)))
  426.        (if (and (stringp f) (file-directory-p f))
  427.            f
  428.          default-directory)))
  429.     (t default-directory)))
  430.  
  431.  
  432. ;;;###autoload
  433. (defun ediff-directories (dir1 dir2 regexp)
  434.   "Run Ediff on a pair of directories, DIR1 and DIR2, comparing files that have
  435. the same name in both. The third argument, REGEXP, is a regular expression that
  436. can be used to filter out certain file names."
  437.   (interactive
  438.    (let ((dir-A (ediff-get-default-directory-name))
  439.      f)
  440.      (list (setq f (ediff-read-file-name "Directory A to compare:" dir-A nil))
  441.        (ediff-read-file-name "Directory B to compare:" 
  442.                  (if ediff-use-last-dir
  443.                      ediff-last-dir-B 
  444.                    (ediff-strip-last-dir f))
  445.                  nil)
  446.        (read-string "Filter through regular expression: "
  447.             nil 'ediff-filtering-regexp-history)
  448.        )))
  449.   (ediff-directories-internal
  450.    dir1 dir2 nil regexp 'ediff-files 'ediff-directories
  451.    ))
  452.  
  453. ;;;###autoload
  454. (defalias 'edirs 'ediff-directories)
  455.  
  456.  
  457. ;;;###autoload
  458. (defun ediff-directory-revisions (dir1 regexp)
  459.   "Run Ediff on a directory, DIR1, comparing its files with their revisions.
  460. The second argument, REGEXP, is a regular expression that filters the file
  461. names. Only the files that are under revision control are taken into account."
  462.   (interactive
  463.    (let ((dir-A (ediff-get-default-directory-name)))
  464.      (list (ediff-read-file-name
  465.         "Directory to compare with revision:" dir-A nil)
  466.        (read-string "Filter through regular expression: "
  467.             nil 'ediff-filtering-regexp-history)
  468.        )))
  469.   (ediff-directory-revisions-internal
  470.    dir1 regexp 'ediff-revision 'ediff-directory-revisions
  471.    ))
  472.  
  473. ;;;###autoload
  474. (defalias 'edir-revisions 'ediff-directory-revisions)
  475.  
  476.  
  477. ;;;###autoload
  478. (defun ediff-directories3 (dir1 dir2 dir3 regexp)
  479.   "Run Ediff on three directories, DIR1, DIR2, and DIR3, comparing files that
  480. have the same name in all three. The last argument, REGEXP, is a regular
  481. expression that can be used to filter out certain file names."
  482.   (interactive
  483.    (let ((dir-A (ediff-get-default-directory-name))
  484.      f)
  485.      (list (setq f (ediff-read-file-name "Directory A to compare:" dir-A nil))
  486.        (setq f (ediff-read-file-name "Directory B to compare:" 
  487.                      (if ediff-use-last-dir
  488.                          ediff-last-dir-B 
  489.                        (ediff-strip-last-dir f))
  490.                      nil))
  491.        (ediff-read-file-name "Directory C to compare:" 
  492.                  (if ediff-use-last-dir
  493.                      ediff-last-dir-C 
  494.                    (ediff-strip-last-dir f))
  495.                  nil)
  496.        (read-string "Filter through regular expression: "
  497.             nil 'ediff-filtering-regexp-history)
  498.        )))
  499.   (ediff-directories-internal
  500.    dir1 dir2 dir3 regexp 'ediff-files3 'ediff-directories3
  501.    ))
  502.  
  503. ;;;###autoload
  504. (defalias 'edirs3 'ediff-directories3)
  505.  
  506. ;;;###autoload
  507. (defun ediff-merge-directories (dir1 dir2 regexp)
  508.   "Run Ediff on a pair of directories, DIR1 and DIR2, merging files that have
  509. the same name in both. The third argument, REGEXP, is a regular expression that
  510. can be used to filter out certain file names."
  511.   (interactive
  512.    (let ((dir-A (ediff-get-default-directory-name))
  513.      f)
  514.      (list (setq f (ediff-read-file-name "Directory A to merge:" dir-A nil))
  515.        (ediff-read-file-name "Directory B to merge:" 
  516.                  (if ediff-use-last-dir
  517.                      ediff-last-dir-B 
  518.                    (ediff-strip-last-dir f))
  519.                  nil)
  520.        (read-string "Filter through regular expression: "
  521.             nil 'ediff-filtering-regexp-history)
  522.        )))
  523.   (ediff-directories-internal
  524.    dir1 dir2 nil regexp 'ediff-merge-files 'ediff-merge-directories
  525.    ))
  526.  
  527. ;;;###autoload
  528. (defalias 'edirs-merge 'ediff-merge-directories)
  529.  
  530. ;;;###autoload
  531. (defun ediff-merge-directories-with-ancestor (dir1 dir2 ancestor-dir regexp)
  532.   "Merge files in directories DIR1 and DIR2 using files in ANCESTOR-DIR as ancestors.
  533. Ediff merges files that have identical names in DIR1, DIR2. If a pair of files
  534. in DIR1 and DIR2 doesn't have an ancestor in ANCESTOR-DIR, Ediff will merge
  535. without ancestor. The fourth argument, REGEXP, is a regular expression that
  536. can be used to filter out certain file names."
  537.   (interactive
  538.    (let ((dir-A (ediff-get-default-directory-name))
  539.      f)
  540.      (list (setq f (ediff-read-file-name "Directory A to merge:" dir-A nil))
  541.        (setq f (ediff-read-file-name "Directory B to merge:" 
  542.                  (if ediff-use-last-dir
  543.                      ediff-last-dir-B 
  544.                    (ediff-strip-last-dir f))
  545.                  nil))
  546.        (ediff-read-file-name "Ancestor directory:"
  547.                  (if ediff-use-last-dir
  548.                      ediff-last-dir-C 
  549.                    (ediff-strip-last-dir f))
  550.                  nil)
  551.        (read-string "Filter through regular expression: "
  552.             nil 'ediff-filtering-regexp-history)
  553.        )))
  554.   (ediff-directories-internal
  555.    dir1 dir2 ancestor-dir regexp
  556.    'ediff-merge-files-with-ancestor 'ediff-merge-directories-with-ancestor
  557.    ))
  558.  
  559. ;;;###autoload
  560. (defun ediff-merge-directory-revisions (dir1 regexp)
  561.   "Run Ediff on a directory, DIR1, merging its files with their revisions.
  562. The second argument, REGEXP, is a regular expression that filters the file
  563. names. Only the files that are under revision control are taken into account."
  564.   (interactive
  565.    (let ((dir-A (ediff-get-default-directory-name)))
  566.      (list (ediff-read-file-name
  567.         "Directory to merge with revisions:" dir-A nil)
  568.        (read-string "Filter through regular expression: "
  569.             nil 'ediff-filtering-regexp-history)
  570.        )))
  571.   (ediff-directory-revisions-internal
  572.    dir1 regexp 'ediff-merge-revisions 'ediff-merge-directory-revisions
  573.    ))
  574.  
  575. ;;;###autoload
  576. (defalias 'edir-merge-revisions 'ediff-merge-directory-revisions)
  577.  
  578. ;;;###autoload
  579. (defun ediff-merge-directory-revisions-with-ancestor (dir1 regexp)
  580.   "Run Ediff on a directory, DIR1, merging its files with their revisions and ancestors.
  581. The second argument, REGEXP, is a regular expression that filters the file
  582. names. Only the files that are under revision control are taken into account."
  583.   (interactive
  584.    (let ((dir-A (ediff-get-default-directory-name)))
  585.      (list (ediff-read-file-name
  586.         "Directory to merge with revisions and ancestors:" dir-A nil)
  587.        (read-string "Filter through regular expression: "
  588.             nil 'ediff-filtering-regexp-history)
  589.        )))
  590.   (ediff-directory-revisions-internal
  591.    dir1 regexp 'ediff-merge-revisions-with-ancestor
  592.    'ediff-merge-directory-revisions-with-ancestor
  593.    ))
  594.  
  595. ;;;###autoload
  596. (defalias
  597.   'edir-merge-revisions-with-ancestor
  598.   'ediff-merge-directory-revisions-with-ancestor) 
  599.  
  600. ;;;###autoload
  601. (defalias 'edirs-merge-with-ancestor 'ediff-merge-directories-with-ancestor)
  602.  
  603. ;; Run ediff-action (ediff-files, ediff-merge, ediff-merge-with-ancestors)
  604. ;; on a pair of directories (three directories, in case of ancestor).
  605. ;; The third argument, REGEXP, is a regular expression that can be used to
  606. ;; filter out certain file names.
  607. ;; JOBNAME is the symbol indicating the meta-job to be performed.
  608. (defun ediff-directories-internal (dir1 dir2 dir3 regexp 
  609.                     action jobname 
  610.                     &optional startup-hooks)
  611.   ;; ediff-read-file-name is set to attach a previously entered file name if
  612.   ;; the currently entered file is a directory. This code takes care of that.
  613.   (setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1))
  614.     dir2 (if (file-directory-p dir2) dir2 (file-name-directory dir2)))
  615.  
  616.   (if (stringp dir3)
  617.       (setq dir3 (if (file-directory-p dir3) dir3 (file-name-directory dir3))))
  618.  
  619.   (cond ((string= dir1 dir2)
  620.      (error "Directories A and B are the same: %s" dir1))
  621.     ((and (eq jobname 'ediff-directories3)
  622.           (string= dir1 dir3))
  623.      (error "Directories A and C are the same: %s" dir1))
  624.     ((and (eq jobname 'ediff-directories3)
  625.           (string= dir2 dir3))
  626.      (error "Directories B and C are the same: %s" dir1)))
  627.  
  628.   (let (diffs ; var where ediff-intersect-directories returns the diff list
  629.     file-list meta-buf)
  630.     (setq file-list (ediff-intersect-directories 
  631.              jobname 'diffs regexp dir1 dir2 dir3))
  632.     (setq startup-hooks
  633.       ;; this sets various vars in the meta buffer inside
  634.       ;; ediff-prepare-meta-buffer
  635.       (cons (` (lambda ()
  636.              ;; tell what to do if the user clicks on a session record
  637.              (setq ediff-session-action-function (quote (, action)))
  638.              ;; set ediff-dir-difference-list 
  639.              (setq ediff-dir-difference-list (quote (, diffs)))))
  640.         startup-hooks))
  641.     (setq meta-buf (ediff-prepare-meta-buffer 
  642.             'ediff-filegroup-action
  643.             file-list
  644.             "*Ediff Session Group Panel"
  645.             'ediff-redraw-directory-group-buffer
  646.             jobname
  647.             startup-hooks))
  648.     (ediff-show-meta-buffer meta-buf)
  649.     ))
  650.  
  651. (defun ediff-directory-revisions-internal (dir1 regexp action jobname 
  652.                         &optional startup-hooks)
  653.   (setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1)))
  654.   (let (file-list meta-buf)
  655.     (setq file-list
  656.       (ediff-get-directory-files-under-revision jobname regexp dir1))
  657.     (setq startup-hooks
  658.       ;; this sets various vars in the meta buffer inside
  659.       ;; ediff-prepare-meta-buffer
  660.       (cons (` (lambda ()
  661.              ;; tell what to do if the user clicks on a session record
  662.              (setq ediff-session-action-function (quote (, action)))
  663.              ))
  664.         startup-hooks))
  665.     (setq meta-buf (ediff-prepare-meta-buffer 
  666.             'ediff-filegroup-action
  667.             file-list
  668.             "*Ediff Session Group Panel"
  669.             'ediff-redraw-directory-group-buffer
  670.             jobname
  671.             startup-hooks))
  672.     (ediff-show-meta-buffer meta-buf)
  673.     ))
  674.  
  675.  
  676. ;;; Compare regions and windows
  677.  
  678. ;;;###autoload
  679. (defun ediff-windows-wordwise (dumb-mode &optional wind-A wind-B startup-hooks)
  680.   "Compare WIND-A and WIND-B, which are selected by clicking, wordwise.
  681. With prefix argument, DUMB-MODE, or on a non-windowing display, works as
  682. follows:
  683. If WIND-A is nil, use selected window.
  684. If WIND-B is nil, use window next to WIND-A."
  685.   (interactive "P")
  686.   (ediff-windows dumb-mode wind-A wind-B
  687.          startup-hooks 'ediff-windows-wordwise 'word-mode))
  688.          
  689. ;;;###autoload
  690. (defun ediff-windows-linewise (dumb-mode &optional wind-A wind-B startup-hooks)
  691.   "Compare WIND-A and WIND-B, which are selected by clicking, linewise.
  692. With prefix argument, DUMB-MODE, or on a non-windowing display, works as
  693. follows:
  694. If WIND-A is nil, use selected window.
  695. If WIND-B is nil, use window next to WIND-A."
  696.   (interactive "P")
  697.   (ediff-windows dumb-mode wind-A wind-B
  698.          startup-hooks 'ediff-windows-linewise nil))
  699.       
  700. ;; Compare WIND-A and WIND-B, which are selected by clicking.
  701. ;; With prefix argument, DUMB-MODE, or on a non-windowing display,
  702. ;; works as follows:
  703. ;; If WIND-A is nil, use selected window.
  704. ;; If WIND-B is nil, use window next to WIND-A.
  705. (defun ediff-windows (dumb-mode wind-A wind-B startup-hooks job-name word-mode)
  706.   (if (or dumb-mode (not (ediff-window-display-p)))
  707.       (setq wind-A (ediff-get-next-window wind-A nil)
  708.         wind-B (ediff-get-next-window wind-B wind-A))
  709.     (setq wind-A (ediff-get-window-by-clicking wind-A nil 1)
  710.       wind-B (ediff-get-window-by-clicking wind-B wind-A 2)))
  711.       
  712.   (let ((buffer-A (window-buffer wind-A))
  713.     (buffer-B (window-buffer wind-B))
  714.     beg-A end-A beg-B end-B)
  715.     
  716.     (save-excursion
  717.       (save-window-excursion
  718.     (sit-for 0) ; sync before using window-start/end -- a precaution
  719.     (select-window wind-A)
  720.     (setq beg-A (window-start)
  721.           end-A (window-end))
  722.     (select-window wind-B)
  723.     (setq beg-B (window-start)
  724.           end-B (window-end))))
  725.     (ediff-regions-internal
  726.      buffer-A beg-A end-A buffer-B beg-B end-B
  727.      startup-hooks job-name word-mode)))
  728.      
  729. ;;;###autoload
  730. (defun ediff-regions-wordwise (buffer-A buffer-B &optional startup-hooks)
  731.   "Run Ediff on a pair of regions in two different buffers.
  732. Regions \(i.e., point and mark\) are assumed to be set in advance.
  733. This function is effective only for relatively small regions, up to 200
  734. lines. For large regions, use `ediff-regions-linewise'."
  735.   (interactive 
  736.    (let (bf)
  737.      (list (setq bf (read-buffer "Region's A buffer: "
  738.                  (ediff-other-buffer "") t))
  739.        (read-buffer "Region's B buffer: "
  740.             (progn
  741.               ;; realign buffers so that two visible bufs will be
  742.               ;; at the top
  743.               (save-window-excursion (other-window 1))
  744.               (ediff-other-buffer bf))
  745.             t))))
  746.   (if (not (ediff-buffer-live-p buffer-A))
  747.       (error "Buffer %S doesn't exist" buffer-A))
  748.   (if (not (ediff-buffer-live-p buffer-B))
  749.       (error "Buffer %S doesn't exist" buffer-B))
  750.   
  751.   
  752.   (let (reg-A-beg reg-A-end reg-B-beg reg-B-end)
  753.     (save-excursion
  754.       (set-buffer buffer-A)
  755.       (setq reg-A-beg (region-beginning)
  756.         reg-A-end (region-end))
  757.       (set-buffer buffer-B)
  758.       (setq reg-B-beg (region-beginning)
  759.         reg-B-end (region-end)))
  760.         
  761.     (ediff-regions-internal
  762.      (get-buffer buffer-A) reg-A-beg reg-A-end
  763.      (get-buffer buffer-B) reg-B-beg reg-B-end
  764.      startup-hooks 'ediff-regions-wordwise 'word-mode)))
  765.      
  766. ;;;###autoload
  767. (defun ediff-regions-linewise (buffer-A buffer-B &optional startup-hooks)
  768.   "Run Ediff on a pair of regions in two different buffers.
  769. Regions \(i.e., point and mark\) are assumed to be set in advance.
  770. Each region is enlarged to contain full lines.
  771. This function is effective for large regions, over 100-200
  772. lines. For small regions, use `ediff-regions-wordwise'."
  773.   (interactive 
  774.    (let (bf)
  775.      (list (setq bf (read-buffer "Region A's buffer: "
  776.                  (ediff-other-buffer "") t))
  777.        (read-buffer "Region B's buffer: "
  778.             (progn
  779.               ;; realign buffers so that two visible bufs will be
  780.               ;; at the top
  781.               (save-window-excursion (other-window 1))
  782.               (ediff-other-buffer bf))
  783.             t))))
  784.   (if (not (ediff-buffer-live-p buffer-A))
  785.       (error "Buffer %S doesn't exist" buffer-A))
  786.   (if (not (ediff-buffer-live-p buffer-B))
  787.       (error "Buffer %S doesn't exist" buffer-B))
  788.   
  789.   (let (reg-A-beg reg-A-end reg-B-beg reg-B-end)
  790.     (save-excursion
  791.       (set-buffer buffer-A)
  792.       (setq reg-A-beg (region-beginning)
  793.         reg-A-end (region-end))
  794.       ;; enlarge the region to hold full lines
  795.       (goto-char reg-A-beg) 
  796.       (beginning-of-line)
  797.       (setq reg-A-beg (point))
  798.       (goto-char reg-A-end) 
  799.       (end-of-line)
  800.       (or (eobp) (forward-char)) ; include the newline char
  801.       (setq reg-A-end (point))
  802.       
  803.       (set-buffer buffer-B)
  804.       (setq reg-B-beg (region-beginning)
  805.         reg-B-end (region-end))
  806.       ;; enlarge the region to hold full lines
  807.       (goto-char reg-A-beg) 
  808.       (goto-char reg-B-beg) 
  809.       (beginning-of-line)
  810.       (setq reg-B-beg (point))
  811.       (goto-char reg-B-end) 
  812.       (end-of-line)
  813.       (or (eobp) (forward-char)) ; include the newline char
  814.       (setq reg-B-end (point))
  815.       ) ; save excursion
  816.         
  817.     (ediff-regions-internal
  818.      (get-buffer buffer-A) reg-A-beg reg-A-end
  819.      (get-buffer buffer-B) reg-B-beg reg-B-end
  820.      startup-hooks 'ediff-regions-linewise nil))) ; no word mode
  821.     
  822. ;; compare region beg-A to end-A of buffer-A
  823. ;; to regions beg-B -- end-B in buffer-B. 
  824. (defun ediff-regions-internal (buffer-A beg-A end-A buffer-B beg-B end-B
  825.                     startup-hooks job-name word-mode)
  826.   (let ((tmp-buffer (get-buffer-create ediff-tmp-buffer))
  827.     overl-A overl-B
  828.     file-A file-B)
  829.     
  830.     ;; in case beg/end-A/B aren't markers--make them into markers
  831.     (ediff-eval-in-buffer buffer-A
  832.       (setq beg-A (move-marker (make-marker) beg-A)
  833.         end-A (move-marker (make-marker) end-A)))
  834.     (ediff-eval-in-buffer buffer-B
  835.       (setq beg-B (move-marker (make-marker) beg-B)
  836.         end-B (move-marker (make-marker) end-B)))
  837.     
  838.     (if (and (eq buffer-A buffer-B)
  839.          (or (and (< beg-A end-B) (<= beg-B beg-A))   ; b-B b-A e-B
  840.          (and (< beg-B end-A) (<= end-A end-B)))) ; b-B e-A e-B
  841.     (progn
  842.       (with-output-to-temp-buffer ediff-msg-buffer
  843.         (princ "
  844. You have requested to compare overlapping regions of the same buffer.
  845.  
  846. In this case, Ediff's highlighting may be confusing---in the same window,
  847. you may see highlighted regions that belong to different regions.
  848.  
  849. Continue anyway? (y/n) "))
  850.  
  851.       (if (y-or-n-p "Continue anyway? ")
  852.           ()
  853.         (error "%S aborted" job-name))))
  854.         
  855.     ;; make file-A
  856.     (if word-mode
  857.     (ediff-wordify beg-A end-A buffer-A tmp-buffer)
  858.       (ediff-copy-to-buffer beg-A end-A buffer-A tmp-buffer))
  859.     (setq file-A (ediff-make-temp-file tmp-buffer "regA"))
  860.     
  861.     ;; make file-B
  862.     (if word-mode
  863.     (ediff-wordify beg-B end-B buffer-B tmp-buffer)
  864.       (ediff-copy-to-buffer beg-B end-B buffer-B tmp-buffer))
  865.     (setq file-B (ediff-make-temp-file tmp-buffer "regB"))
  866.      
  867.     (setq overl-A (ediff-make-bullet-proof-overlay beg-A end-A buffer-A))
  868.     (setq overl-B (ediff-make-bullet-proof-overlay beg-B end-B buffer-B))
  869.     (ediff-setup buffer-A file-A
  870.          buffer-B file-B
  871.          nil nil        ; buffer & file C
  872.          (cons (` (lambda ()
  873.                 (delete-file (, file-A))
  874.                 (delete-file (, file-B))))
  875.                startup-hooks)
  876.          (list (cons 'ediff-word-mode  word-mode)
  877.                (cons 'ediff-narrow-bounds (list overl-A overl-B))
  878.                (cons 'ediff-job-name job-name))
  879.          )
  880.     ))
  881.     
  882.  
  883. ;;; Merge files and buffers
  884.   
  885. ;;;###autoload
  886. (defalias 'ediff-merge 'ediff-merge-files)
  887.   
  888. (defsubst ediff-merge-on-startup ()
  889.   (ediff-do-merge 0)
  890.   (ediff-eval-in-buffer ediff-buffer-C
  891.     (set-buffer-modified-p nil)))
  892.  
  893. ;;;###autoload
  894. (defun ediff-merge-files (file-A file-B &optional startup-hooks)
  895.   "Merge two files without ancestor."
  896.   (interactive
  897.    (let ((dir-A (if ediff-use-last-dir
  898.             ediff-last-dir-A
  899.           default-directory))
  900.      dir-B f)
  901.      (list (setq f (ediff-read-file-name
  902.             "File A to merge" dir-A
  903.             (ediff-get-default-file-name)))
  904.        (ediff-read-file-name "File B to merge" 
  905.                  (setq dir-B
  906.                        (if ediff-use-last-dir
  907.                        ediff-last-dir-B 
  908.                      (file-name-directory f)))
  909.                  (progn
  910.                    (setq file-name-history
  911.                      (cons (ediff-abbreviate-file-name
  912.                         (expand-file-name
  913.                          (file-name-nondirectory f)
  914.                          dir-B))
  915.                            file-name-history))
  916.                    f))
  917.        )))
  918.   (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
  919.   (ediff-files-internal file-A 
  920.             (if (file-directory-p file-B)
  921.                 (expand-file-name
  922.                  (file-name-nondirectory file-A) file-B)
  923.               file-B)
  924.               nil ; file-C
  925.               startup-hooks
  926.               'ediff-merge-files))
  927.               
  928. ;;;###autoload
  929. (defun ediff-merge-files-with-ancestor (file-A file-B file-ancestor
  930.                            &optional startup-hooks)
  931.   "Merge two files with ancestor."
  932.   (interactive
  933.    (let ((dir-A (if ediff-use-last-dir
  934.             ediff-last-dir-A
  935.           default-directory))
  936.      dir-B dir-ancestor f ff)
  937.      (list (setq f (ediff-read-file-name
  938.             "File A to merge" dir-A
  939.             (ediff-get-default-file-name)))
  940.        (setq ff (ediff-read-file-name "File B to merge" 
  941.                       (setq dir-B
  942.                         (if ediff-use-last-dir
  943.                             ediff-last-dir-B 
  944.                           (file-name-directory f)))
  945.                       (progn
  946.                         (setq file-name-history
  947.                           (cons
  948.                            (ediff-abbreviate-file-name
  949.                             (expand-file-name
  950.                              (file-name-nondirectory f)
  951.                              dir-B))
  952.                            file-name-history))
  953.                         f)))
  954.        (ediff-read-file-name "Ancestor file" 
  955.                  (setq dir-ancestor
  956.                        (if ediff-use-last-dir
  957.                        ediff-last-dir-ancestor
  958.                      (file-name-directory ff)))
  959.                  (progn
  960.                    (setq file-name-history
  961.                      (cons (ediff-abbreviate-file-name
  962.                         (expand-file-name
  963.                          (file-name-nondirectory ff)
  964.                          dir-ancestor))
  965.                            file-name-history))
  966.                    ff))
  967.        )))
  968.   (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
  969.   (ediff-files-internal file-A 
  970.             (if (file-directory-p file-B)
  971.                 (expand-file-name
  972.                  (file-name-nondirectory file-A) file-B)
  973.               file-B)
  974.               file-ancestor
  975.               startup-hooks
  976.               'ediff-merge-files-with-ancestor))
  977.               
  978. ;;;###autoload
  979. (defalias 'ediff-merge-with-ancestor 'ediff-merge-files-with-ancestor)
  980.               
  981. ;;;###autoload
  982. (defun ediff-merge-buffers (buffer-A buffer-B &optional startup-hooks job-name)
  983.   "Merge buffers without ancestor."
  984.   (interactive 
  985.    (let (bf)
  986.      (list (setq bf (read-buffer "Buffer A to merge: "
  987.                  (ediff-other-buffer "") t))
  988.        (read-buffer "Buffer B to merge: "
  989.             (progn
  990.               ;; realign buffers so that two visible bufs will be
  991.               ;; at the top
  992.               (save-window-excursion (other-window 1))
  993.               (ediff-other-buffer bf))
  994.             t))))
  995.   
  996.   (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
  997.   (or job-name (setq job-name 'ediff-merge-buffers))
  998.   (ediff-buffers-internal
  999.    buffer-A buffer-B nil startup-hooks job-name))
  1000.    
  1001. ;;;###autoload
  1002. (defun ediff-merge-buffers-with-ancestor (buffer-A 
  1003.                       buffer-B buffer-ancestor
  1004.                       &optional startup-hooks job-name)
  1005.   "Merge buffers with ancestor."
  1006.   (interactive 
  1007.    (let (bf bff)
  1008.      (list (setq bf (read-buffer "Buffer A to merge: "
  1009.                  (ediff-other-buffer "") t))
  1010.        (setq bff (read-buffer "Buffer B to merge: "
  1011.                   (progn
  1012.                     ;; realign buffers so that two visible
  1013.                     ;; bufs will be at the top
  1014.                     (save-window-excursion (other-window 1))
  1015.                     (ediff-other-buffer bf))
  1016.                   t))
  1017.        (read-buffer "Ancestor buffer: "
  1018.                   (progn
  1019.                     ;; realign buffers so that three visible
  1020.                     ;; bufs will be at the top
  1021.                     (save-window-excursion (other-window 1))
  1022.                     (ediff-other-buffer (list bf bff)))
  1023.                   t)
  1024.        )))
  1025.   
  1026.   (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
  1027.   (or job-name (setq job-name 'ediff-merge-buffers-with-ancestor))
  1028.   (ediff-buffers-internal
  1029.    buffer-A buffer-B buffer-ancestor startup-hooks job-name))
  1030.       
  1031.  
  1032. ;;;###autoload
  1033. (defun ediff-merge-revisions (&optional file startup-hooks)
  1034.   "Run Ediff by merging two revisions of a file.
  1035. The file is the optional FILE argument or the file visited by the current
  1036. buffer."
  1037.   (interactive)
  1038.   (if (stringp file) (find-file file))
  1039.   (let (rev1 rev2)
  1040.     (setq rev1
  1041.       (read-string
  1042.        (format
  1043.         "Version 1 to merge (default: %s's latest version): "
  1044.         (if (stringp file)
  1045.         (file-name-nondirectory file) "current buffer")))
  1046.       rev2
  1047.       (read-string
  1048.        (format
  1049.         "Version 2 to merge (default: %s): "
  1050.         (if (stringp file)
  1051.         (file-name-nondirectory file) "current buffer"))))
  1052.     (ediff-load-version-control)
  1053.     ;; ancestor-revision=nil
  1054.     (funcall
  1055.      (intern (format "%S-ediff-merge-internal" ediff-version-control-package))
  1056.      rev1 rev2 nil startup-hooks)))
  1057.     
  1058.  
  1059. ;;;###autoload
  1060. (defun ediff-merge-revisions-with-ancestor (&optional file startup-hooks)
  1061.   "Run Ediff by merging two revisions of a file with a common ancestor.
  1062. The file is the the optional FILE argument or the file visited by the current
  1063. buffer."
  1064.   (interactive)
  1065.   (if (stringp file) (find-file file))
  1066.   (let (rev1 rev2 ancestor-rev)
  1067.     (setq rev1
  1068.       (read-string
  1069.        (format
  1070.         "Version 1 to merge (default: %s's latest version): "
  1071.         (if (stringp file)
  1072.         (file-name-nondirectory file) "current buffer")))
  1073.       rev2
  1074.       (read-string
  1075.        (format
  1076.         "Version 2 to merge (default: %s): "
  1077.         (if (stringp file)
  1078.         (file-name-nondirectory file) "current buffer")))
  1079.       ancestor-rev
  1080.       (read-string
  1081.        (format
  1082.         "Ancestor version (default: %s): "
  1083.         (if (stringp file)
  1084.         (file-name-nondirectory file) "current buffer"))))
  1085.     (ediff-load-version-control)
  1086.     (funcall
  1087.      (intern (format "%S-ediff-merge-internal" ediff-version-control-package))
  1088.      rev1 rev2 ancestor-rev startup-hooks)))
  1089.  
  1090. ;;;###autoload
  1091. (defun run-ediff-from-cvs-buffer (pos)
  1092.   "Run Ediff-merge on appropriate revisions of the selected file.
  1093. First run after `M-x cvs-update'. Then place the cursor on a lide describing a
  1094. file and then run `run-ediff-from-cvs-buffer'."
  1095.   (interactive "d")
  1096.   (ediff-load-version-control)
  1097.   (let ((tin (tin-locate cvs-cookie-handle pos)))
  1098.     (if tin
  1099.     (cvs-run-ediff-on-file-descriptor tin)
  1100.       (error "There is no file to merge"))))
  1101.      
  1102.      
  1103. ;;; Apply patch
  1104.  
  1105. ;;;###autoload
  1106. (defun ediff-patch-file ()
  1107.   "Run Ediff by patching SOURCE-FILENAME."
  1108.   ;; This now returns the control buffer
  1109.   (interactive)
  1110.   (let (source-dir source-file patch-buf)
  1111.     (require 'ediff-ptch)
  1112.     (setq patch-buf (ediff-get-patch-buffer))
  1113.     (setq source-dir (cond (ediff-use-last-dir ediff-last-dir-patch)
  1114.                ((and (not ediff-patch-default-directory)
  1115.                  (buffer-file-name patch-buf))
  1116.                 (file-name-directory
  1117.                  (expand-file-name
  1118.                   (buffer-file-name patch-buf))))
  1119.                (t default-directory)))
  1120.     (setq source-file
  1121.       ;; the default is the directory, not the visited file name
  1122.       (ediff-read-file-name "Which file to patch? " source-dir source-dir))
  1123.     (ediff-dispatch-file-patching-job patch-buf source-file)))
  1124.  
  1125. ;;;###autoload
  1126. (defun ediff-patch-buffer ()
  1127.   "Run Ediff by patching BUFFER-NAME."
  1128.   (interactive)
  1129.   (let (patch-buf)
  1130.     (require 'ediff-ptch)
  1131.     (setq patch-buf (ediff-get-patch-buffer))
  1132.     (ediff-patch-buffer-internal
  1133.      patch-buf
  1134.      (read-buffer "Which buffer to patch? "
  1135.           (cond ((eq patch-buf (current-buffer))
  1136.              (window-buffer (other-window 1)))
  1137.             (t (current-buffer)))
  1138.           'must-match))))
  1139.   
  1140. ;;;###autoload
  1141. (defalias 'epatch 'ediff-patch-file)
  1142. ;;;###autoload
  1143. (defalias 'epatch-buffer 'ediff-patch-buffer)
  1144.  
  1145.  
  1146.  
  1147.  
  1148. ;;; Versions Control functions      
  1149.       
  1150. ;;;###autoload
  1151. (defun ediff-revision (&optional file startup-hooks)
  1152.   "Run Ediff by comparing versions of a file.
  1153. The file is an optional FILE argument or the file visited by the current
  1154. buffer. Use `vc.el' or `rcs.el' depending on `ediff-version-control-package'."
  1155.   ;; if buffer is non-nil, use that buffer instead of the current buffer
  1156.   (interactive "P")
  1157.   (if (stringp file) (find-file file))
  1158.   (let (rev1 rev2)
  1159.     (setq rev1
  1160.       (read-string
  1161.        (format "Version 1 to compare (default: %s's latest version): "
  1162.            (if (stringp file)
  1163.                (file-name-nondirectory file) "current buffer")))
  1164.       rev2
  1165.       (read-string 
  1166.        (format "Version 2 to compare (default: %s): "
  1167.            (if (stringp file)
  1168.                (file-name-nondirectory file) "current buffer"))))
  1169.     (ediff-load-version-control)
  1170.     (funcall
  1171.      (intern (format "%S-ediff-internal" ediff-version-control-package))
  1172.      rev1 rev2 startup-hooks)
  1173.     ))
  1174.    
  1175.    
  1176. ;; Test if version control package is loaded and load if not
  1177. ;; Is SILENT is non-nil, don't report error if package is not found.
  1178. (defun ediff-load-version-control (&optional silent)
  1179.   (require 'ediff-vers)
  1180.   (or (featurep ediff-version-control-package)
  1181.       (if (locate-library (symbol-name ediff-version-control-package))
  1182.       (progn
  1183.         (message "") ; kill the message from `locate-library'
  1184.         (require ediff-version-control-package))
  1185.     (or silent
  1186.         (error "Version control package %S.el not found. Use vc.el instead"
  1187.            ediff-version-control-package)))))
  1188.  
  1189.  
  1190. ;;;###autoload
  1191. (defun ediff-version ()
  1192.   "Return string describing the version of Ediff.
  1193. When called interactively, displays the version."
  1194.   (interactive)
  1195.   (if (interactive-p)
  1196.       (message (ediff-version))
  1197.     (format "Ediff %s of %s" ediff-version ediff-date)))
  1198.  
  1199.  
  1200. ;;;###autoload
  1201. (defun ediff-documentation ()
  1202.   "Display Ediff's manual."
  1203.   (interactive)
  1204.   (let ((ctl-window ediff-control-window)
  1205.     (ctl-buf ediff-control-buffer))
  1206.  
  1207.     (ediff-skip-unsuitable-frames)
  1208.     (condition-case nil
  1209.     (progn
  1210.       (pop-to-buffer (get-buffer-create "*info*"))
  1211.       (info (if ediff-xemacs-p "ediff.info" "ediff"))
  1212.       (message "Type `i' to search for a specific topic"))
  1213.       (error (beep 1)
  1214.          (with-output-to-temp-buffer ediff-msg-buffer
  1215.            (princ (format "
  1216. The Info file for Ediff does not seem to be installed.
  1217.  
  1218. This file is part of the distribution of %sEmacs.
  1219. Please contact your system administrator. "
  1220.                   (if ediff-xemacs-p "X" ""))))
  1221.          (if (window-live-p ctl-window)
  1222.          (progn
  1223.            (select-window ctl-window)
  1224.            (set-window-buffer ctl-window ctl-buf)))))))
  1225.     
  1226.  
  1227.  
  1228.  
  1229. ;;; Local Variables:
  1230. ;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
  1231. ;;; eval: (put 'ediff-eval-in-buffer 'lisp-indent-hook 1)
  1232. ;;; End:
  1233.  
  1234. (provide 'ediff)
  1235. (require 'ediff-util)
  1236.  
  1237. ;;; ediff.el ends here
  1238.